# -*- coding: UTF-8 -*-

import xeres

from ui.uxml import component
from ui.uxml import property
from ui.uxml import source
from ui.uxml import package
from ui.uxml import style
from ui.uxml import sheet

#
#	Reads ui definitions and translate them to real window.
#

__all__ = ['load_uxml']

# Generate type from a given name(with namespace).
def __get_type( name ):
	index = name.rfind('.')
	if index == -1 :
		module = "xeres"
		type = name
	else:
		# Get type from specific module.
		index = name.rfind('.')
		module = name[:index]
	type = name[index+1:]
	#print "try to get type" , name
	exp = "from " + module + " import " + type
	try:
		d = {}
		exec exp in d
		return d[type]
	except:
		print "Type (", name, ") not found!"
		return None

# Parse namespace from entry.
def __parse_ns( entry ):
	for name,value in entry.attributes:
		if name.startswith('xmlns:'):
			alias = name[6:]
			return (alias,value)
	return None

# Parse component from uxml entry.
def __parse_comp( name, entry, ns ):
	#print "parse comp" , name
	
	# decompose namespace
	local_ns = __parse_ns(entry)
	if local_ns:
		if ns.has_key( local_ns[0] ) and ns[local_ns[0]] != local_ns[1]:
			print "Warning! Override local namespace might produce unpredictable result!"
		ns[local_ns[0]] = local_ns[1]
	
	# replace namespace	to make full path
	pos = name.find(':')
	if pos != -1:
		namespace = name[0:pos]
		detail = name[pos+1:]
		if not ns.has_key( namespace ):
			print "Error! No such namespace declared! (" , namespace , ")"
			return None
		namespace = ns[namespace]
		name = namespace + '.' + detail

	# get component type	
	type = __get_type( name )
	if type == None:
		return None

	# make definition
	if issubclass( type , xeres.IGuiForm ):
		# Container type
		children = []
		for childname,entity in entry.children:
			comp = __parse_comp( childname, entity, ns.copy() )
			children.append( comp )
		return component.ContainerDef( name, type, entry, children )

	else:
		# Component type
		return component.ComponentDef( name, type, entry )

# Parse a uxml entry.
def load_uxml( uxml_data, filename="?" ):
	
	# elements may be defined
	styles = None
	code = None
	comp = None
	ns = {}
	
	# Parse ui data.
	for name,entity in uxml_data.children:
		# dispatch components
		if name == 'code':
			# a code section
			code = source.SourceDef( entity, filename )

		elif name == 'style':
			# a style definition
			styles = style.parse_style( entity.string )

		else:
			# must be component section.
			if comp != None:
				print "Error! Multiple component definition is not allow"
				return None

			# decompose namespace
			local_ns = __parse_ns(entity)
			if local_ns:
				if ns.has_key( local_ns[0] ) and ns[local_ns[0]] != local_ns[1]:
					print "Warning! Override local namespace might produce unpredictable result!"
				ns[local_ns[0]] = local_ns[1]
			
			pos = name.find(':')
			if pos != -1:
				namespace = name[0:pos]
				detail = name[pos+1:]
				if not ns.has_key( namespace ):
					print "Error! No such namespace declared! (" , namespace , ")"
					return None
			
				namespace = ns[namespace]
				name = namespace + '.' + detail
				
			# dispatch to registered component handler
			comp = __parse_comp( name, entity, ns )
			if comp == None:
				print "Error! Failed to create component definition!"
				return None
	
	# Check defined component.
	if comp == None:
		print "Error! No component defined!"
		return None
	
	# Compile & apply styles.
	if styles and comp:
		candidates = style.expand_candidates(comp)
		#print "expanded candidates" , candidates
		#print "expanded styles" , styles
		for i in styles:
			i.apply(candidates)
		for i in candidates:
			if i.style:
				sheet.compile_property(i)
	
	return package.Package(comp,code,styles)
